import os
import json
import subprocess
from pathlib import Path

from utils import fill_cfg_into_code

def run_c_module_and_capture_output(c_file, include_dirs):
    """Run Python modules and capture output"""
    CFG_dict = None
    c_input = ""
    c_output = ""
    c_description = ""
    try:
        # Using subprocess to call Python modules and obtain output
        result = subprocess.run(
            ['python3', '-m', 'c-cfg', '--filename', c_file, '--include', ":".join(include_dirs)],
            text=True,
            timeout=150,
            capture_output=True,
            check=True
        )
        CFG_dict = json.loads(result.stdout)
        d_file = c_file.replace(".c", "-task.txt")
        if os.path.exists(d_file):
            with open(d_file, "r") as df:
                c_description = df.read()
        else:
            c_description = "No available description."
        return CFG_dict, c_input, c_output, c_description
    except subprocess.CalledProcessError as e:
        print(f"Error processing file {c_file}: {e}")
        return None, "", "", "No available description."
    except subprocess.TimeoutExpired as toe:
        print(f"Timeout processing file {c_file}: {toe}")
        return None, "", "", "No available description."
    except UnicodeDecodeError as ude:
        print(f"Timeout processing file {c_file}: {ude}")
        return None, "", "", "No available description."

def save_c_output_to_json(c_file, CFG_dict, c_input, c_output, c_description, output_dir, include_dirs):
    """Save the output to a separate JSON file"""
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    from parse_c import parse_c_code
    
    try:
        c_code, MAIN_FLAG = parse_c_code(c_file, include_dirs)
    except Exception as e:
        import traceback
        print(f"Fail to extract code snippets:{e}\n{traceback.print_exc()}")
        raise e

    output_path = Path(output_dir) / (Path(c_file).stem + "_output.json")
    fill_cfg_into_code(c_code, CFG_dict)

    if output_path.exists():
        with open(output_path, 'r') as f:
            data = json.load(f)
        if "C" in data:
            data["C"]["CFG"] = CFG_dict 
            data["C"]["code"] = c_code
            data["C"]["main"] = str(MAIN_FLAG)
        data["c_input"] = c_input.strip()
        data["c_output"] = c_output.strip()
        data["c_description"] = c_description.strip()
    else:
        data = {
            "C": {
                "CFG": CFG_dict,
                "code": c_code,
                "main":str(MAIN_FLAG),
            },
            "c_input": c_input.strip(),
            "c_output": c_output.strip(),
            "c_description": c_description.strip(),
        }

    data = {
        "C": {
            "CFG": CFG_dict,
            "code": c_code,
            "main": MAIN_FLAG,
        },
        "c_input": c_input.strip(),
        "c_output": c_output.strip(),
        "c_description": c_description.strip(),
    }

    with open(output_path, 'w') as f:
        json.dump(data, f, indent=4)
    print(f"cfg, input, output, description saved to {output_path}")

def cfg_entry(c_file, output_dir, include_dirs):
    print(f"Extracting cfg, input, output, description.")
    CFG_dict, c_input, c_output, c_description = run_c_module_and_capture_output(c_file, include_dirs)
    if CFG_dict not in (None, {}):
        save_c_output_to_json(c_file, CFG_dict, c_input, c_output, c_description, output_dir, include_dirs)
    else:
        if c_file.endswith(".h"):
            save_c_output_to_json(c_file, CFG_dict, c_input, c_output, c_description, output_dir, include_dirs)
        print(f"The extraction result of {c_file} is empty, ignore it!")

# if __name__ == "__main__":
#     import sys
#     if len(sys.argv) != 3:
#         print("Usage: python parse_cfg_snippets.py <c-directory-to-scan> <output-directory>")
#     else:
#         from utils import system_header_paths
#         cfg_entry(sys.argv[1], sys.argv[2], system_header_paths)


def test_parse_cfg():
    import sys
    import os
    
    # 设置测试源文件和输出目录路径
    test_source_file = "test_files/src/test.c"
    test_output_dir = "test_files/output"
    
    # 创建输出目录
    os.makedirs(test_output_dir, exist_ok=True)
    
    # 可选：创建任务描述文件
    task_file = test_source_file.replace(".c", "-task.txt")
    with open(task_file, "w") as f:
        f.write("Test function that moves a point in 2D space.")
    
    # 模拟命令行参数
    sys.argv = [
        "parse_cfg_snippets.py",
        test_source_file,
        test_output_dir
    ]
    
    # 调用原main函数的逻辑
    from utils import system_header_paths
    cfg_entry(sys.argv[1], sys.argv[2], system_header_paths)

if __name__ == "__main__":
    test_parse_cfg()
